﻿using DataTransfer.Core.Models;
using DataTransfer.Core.Providers;
using DataTransfer.SDK;
using DataTransfer.SDK.Events;
using DataTransfer.SDK.Models;
using MiniFox;
using MiniFox.Components;
using MiniFox.Platform.Applications.Auth;
using MiniFox.Platform.File.Models;

namespace DataTransfer.Core.Services
{
    /// <summary>
    /// 
    /// </summary>
    [AutoRegister]
    public abstract class ExportEngine : Component, IExportEventListener
    {
        DataLoader _dataLoader;
        IExporter _exporter;
        public event EventHandler<ExporterBeforeLoadEventArgs> BeforeLoad;
        public event EventHandler<ExporterAfterLoadEventArgs> AfterLoad;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="exporterName"></param>
        /// <param name="authStateManagement"></param>
        public ExportEngine(string exporterName, IAuthStateManagement authStateManagement)
        {
            ExporterName = exporterName;
            AuthStateManagement = authStateManagement;
        }

        protected IAuthStateManagement AuthStateManagement { get; }
        /// <summary>
        /// 
        /// </summary>
        public string ExporterName
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected virtual IExportConfigProvider Configuration
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        protected internal IExporter Exporter
        {
            get
            {
                _exporter ??= Configuration.GetExporter(ExporterName);
                return _exporter;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected virtual DataLoader CreateDataLoader()
        {
            var type = Exporter.DataLoaderType;
            var instance = Activator.CreateInstance(type, Exporter, AuthStateManagement);
            var loader = instance as DataLoader;
            return loader;
        }
        /// <summary>
        /// 
        /// </summary>
        public DataLoader DataLoader
        {
            get
            {
                _dataLoader ??= CreateDataLoader();
                return _dataLoader;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public abstract string ExtensionName
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        protected virtual FileData CreateUniqueFile(string fileName)
        {
            var fileData = new FileData
            {
                FileId = SequenceGUID.NewGUID()
            };
            fileData.FileName = $"{(string.IsNullOrEmpty(fileName) ? fileData.FileId : fileName)}{ExtensionName}";
            fileData.Group = ExporterName;
            return fileData;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        protected abstract byte[] ExportResultToBytes(object result);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="exportModel"></param>
        /// <returns></returns>
        public virtual FileData Execute(ExportRequest exportModel)
        {
            var dataLoader = DataLoader;
            OnBeforeLoad(new ExporterBeforeLoadEventArgs(exportModel.QueryContent));
            var result = dataLoader.ExecuteLoad(exportModel.QueryContent);
            OnAfterLoad(new ExporterAfterLoadEventArgs(exportModel.QueryContent, result));
            var data = ExportResultToBytes(result);
            var fileData = CreateUniqueFile(exportModel.FileName);
            fileData.Data = data;
            return fileData;
        }

        #region event

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnBeforeLoad(ExporterBeforeLoadEventArgs e)
        {
            BeforeLoad?.Invoke(this, e);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnAfterLoad(ExporterAfterLoadEventArgs e)
        {
            AfterLoad?.Invoke(this, e);
        }
        #endregion
    }

}
